<?php
/**
 * FastApp.
 * 8/18/24
 * @Author 深色的海 (wx:deepsea_0024)
 * @Contact telegram:deepsea159 
 */

namespace App\Marketing\Api\Service;

use App\Fastapp\Api\Service\Account\WalletService;
use App\Fastapp\Exception\TipException;
use App\Fastapp\Model\AccountWallet;
use App\Fastapp\Model\AccountWalletLog;
use App\Mall\Model\MallGoods;
use App\Marketing\Model\MarketingBlindBox;
use App\Marketing\Model\MarketingBlindBoxLog;
use Hyperf\Database\Model\Builder;

class BoxService
{
    public function list(string $code): array
    {
        $list = MarketingBlindBox::query()->select(['id', 'name', 'title', 'icon', 'pool', 'price', 'type', 'config'])
            ->where(['code' => $code])
            ->orderByDesc('sort')->get()->map(function ($item) {
                $item->name = fastapp_lang_text($item->name);
                $item->title = fastapp_lang_text($item->title);
                $item->setHidden(['config']);
                if ($item->type == 2) {
                    $ids = [];
                    foreach ($item->config as $c) $ids = array_merge($ids, $c['goods_id']);
                    $item->goods = $ids;
                } else {
                    $c = $item->config;
                    $item->min = $c[0]['min'];
                    $max = end($c);
                    $item->max = $max['max'];
                }
                return $item;
            });
        $goods_ids = [];
        foreach ($list->pluck('config')->toArray() as $c) {
            foreach ($c as $v) $goods_ids = array_merge($v['goods_id'] ?? []);
        }
        if ($goods_ids) {
            $goods = MallGoods::query()->select(['id', 'name', 'images'])->whereIn('id', $goods_ids)->get()->mapWithKeys(function ($item) {
                $item->name = fastapp_lang_text($item->name);
                return [$item->id => $item];
            })->toArray();
            foreach ($list as $item) {
                $g = [];
                foreach ($item->goods as $gid) $g[] = $goods[$gid];
                $item->goods = $g;
            }
        }
        return ['list' => $list];
    }

    public function log(string $code): array
    {
        $ids = MarketingBlindBox::query()->where(['code' => $code])->pluck('id')->toArray();
        $paginate = MarketingBlindBoxLog::query()->whereIn('box_id', $ids)->orderByDesc('id')->simplePaginate();
        return ['list' => $paginate->items()];
    }

    public function userLog(string $code): array
    {
        $ids = MarketingBlindBox::query()->where(['code' => $code])->pluck('id')->toArray();
        $paginate = MarketingBlindBoxLog::query()->where(['user_id' => get_uid()])->whereIn('box_id', $ids)->orderByDesc('id')->simplePaginate();
        return ['list' => $paginate->items()];
    }

    public function open(array $data): array
    {
        $box = MarketingBlindBox::query()->findOrFail($data['id']);
        $result = [];
        WalletService::dec($data, function (array $data, Builder $query) use ($box, &$result) {
            $field = 'balance';
            $amount = bcmul($box->price, '' . $data['num'], 2);
            /** @var AccountWallet $wallet */
            $wallet = $query->where($field, '>=', $amount)->first();
            if (!$wallet) throw new TipException(fastapp_t('pay.insufficient_funds'));
            $before = $wallet->$field;
            $wallet->$field = bcsub($wallet->$field, $amount, $wallet->currency->trade_precision);
            $wallet->save();
            $probabilities = [];
            foreach ($box->config as $k => $c) {
                $probabilities[$k] = $c['rate'];
            }
            $refunded = [];
            for ($i = 0; $i < $data['num']; $i++) {
                $idx = openBlindBox($probabilities);
                $config = $box->config[$idx];
                if ($box->type == 1) $refunded[] = random_int($config['min'], $config['max']);
                if ($box->type == 2) $refunded[] = $config['goods_id'][array_rand($config['goods_id'])];
            }

            $log = MarketingBlindBoxLog::query()->create([
                'user_id' => $wallet->user_id,
                'box_id' => $box->id,
                'num' => $data['num'],
                'amount' => $amount,
                'type' => $box->type,
                'refunded' => $box->type == 1 ? [array_sum($refunded)] : $refunded,
            ]);
            $log2 = AccountWalletLog::query()->create([
                'user_id' => $wallet->user_id,
                'wallet_id' => $wallet->id,
                'currency_id' => $wallet->currency_id,
                'type' => AccountWalletLog::USE_BALANCE,
                'object_type' => AccountWalletLog::OBJ_TYPE_BLIND_BOX_LOG,
                'object_id' => $log->id,
                'field' => $field,
                'amount' => $amount,
                'before' => $before,
                'after' => $wallet->$field,
            ]);
            $result['log_id'] = $log->id;
            if ($box->type == 1) {
                $result['refunded'] = $log->refunded[0];
                if ($amount < $result['refunded']) {
                    MarketingBlindBox::query()->where(['id' => $data['id']])->decrement('pool', bcsub($result['refunded'], $amount, 2));
                } else {
                    MarketingBlindBox::query()->where(['id' => $data['id']])->increment('pool', bcsub($amount, $result['refunded'], 2));
                }
            } else {
                $result['goods_id'] = $log->refunded;
            }
            $wallet->log_id = $log2->id;
            return $wallet;
        });

        if ($box->type == 1) {
            $result['pool'] = MarketingBlindBox::query()->where(['id' => $data['id']])->value('pool');
            WalletService::inc([
                'amount' => $result['refunded'],
                'type' => AccountWalletLog::RECHARGE,
                'object_type' => AccountWalletLog::OBJ_TYPE_BLIND_BOX_LOG,
                'object_id' => $result['log_id']
            ]);
            return $result;
        }
        $goods = MallGoods::query()->select(['id', 'name', 'images'])->whereIn('id', $result['goods_id'])->get()->mapWithKeys(function ($item) {
            $item->name = fastapp_lang_text($item->name);
            return [$item->id => $item];
        })->toArray();
        foreach ($result['goods_id'] as $gid) {
            $result['list'][] = $goods[$gid];
        }
        return ['list' => $result['list']];
    }
}